﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Collections;
using System.Globalization;
using System.IO;
using System.Resources;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text.RegularExpressions;
using System.Configuration;
using Memcached.ClientLibrary;
using CustomCommon.Connons;

namespace CustomCommon
{
    public class MyMemCachedClient : MemcachedClient
    {
        private const string VALUE = "VALUE"; // start of value line from server
        private const string STATS = "STAT"; // start of stats line from server
        private const string DELETED = "DELETED"; // successful deletion
        private const string NOTFOUND = "NOT_FOUND"; // record not found for delete or incr/decr
        private const string STORED = "STORED"; // successful store of data
        private const string NOTSTORED = "NOT_STORED"; // data not stored
        private const string OK = "OK"; // success
        private const string END = "END"; // end of data from server
        private const string ERROR = "ERROR"; // invalid command name from client
        private const string CLIENT_ERROR = "CLIENT_ERROR"; // client error in input line - invalid protocol
        private const string SERVER_ERROR = "SERVER_ERROR";	// server error

        public MyMemCachedClient() : base() { }

        //public MyMemCachedClient(string poolName) : base(poolName){}

        //public MyMemCachedClient(string poolName) : base(poolName){}
        /// <summary>
        /// Retrieves stats for passed in servers (or all servers).
        /// 
        /// Returns a map keyed on the servername.
        /// The value is another map which contains stats
        /// with stat name as key and value as value.
        /// </summary>
        /// <param name="servers">string array of servers to retrieve stats from, or all if this is null</param>
        /// <param name="command">�����в������ò���ΪDiscuzNT�޸İ�</param>
        /// <returns>Stats map</returns>
        public Hashtable Stats(ArrayList servers, string command, out string message)
        {
            message = "";

            // get SockIOPool instance
            SockIOPool pool = SockIOPool.GetInstance(PoolName);

            // return false if unable to get SockIO obj
            if (pool == null)
            {
                //if(log.IsErrorEnabled)
                //{
                //    log.Error(GetLocalizedString("unable to get socket pool"));
                //}
                return null;
            }

            // get all servers and iterate over them
            if (servers == null)
                servers = pool.Servers;

            // if no servers, then return early
            if (servers == null || servers.Count <= 0)
            {
                //if(log.IsErrorEnabled)
                //{
                //    log.Error(GetLocalizedString("stats no servers"));
                //}
                return null;
            }

            // array of stats Hashtables
            Hashtable statsMaps = new Hashtable();

            for (int i = 0; i < servers.Count; i++)
            {

                SockIO sock = pool.GetConnection((string)servers[i]);
                if (sock == null)
                {
                    //if(log.IsErrorEnabled)
                    //{
                    //    log.Error(GetLocalizedString("unable to connect").Replace("$$Server$$", servers[i].ToString()));
                    //}                
                    //continue;
                    message = "connect error";
                    return null;
                }

                // build command
                command = Utils.StrIsNullOrEmpty(command) ? "stats\r\n" : command + "\r\n";

                try
                {
                    sock.Write(UTF8Encoding.UTF8.GetBytes(command));
                    sock.Flush();

                    // map to hold key value pairs
                    Hashtable stats = new Hashtable();

                    // loop over results
                    while (true)
                    {
                        string line = sock.ReadLine();
                        //if(log.IsDebugEnabled)
                        //{
                        //    log.Debug(GetLocalizedString("stats line").Replace("$$Line$$", line));
                        //}

                        if (line.StartsWith(STATS))
                        {
                            string[] info = line.Split(' ');
                            string key = info[1];
                            string val = info[2];

                            //if(log.IsDebugEnabled)
                            //{
                            //    log.Debug(GetLocalizedString("stats success").Replace("$$Key$$", key).Replace("$$Value$$", val));
                            //}

                            stats[key] = val;

                        }
                        else if (line.StartsWith("ITEM"))
                        {
                            string[] info = line.Split('[');
                            string key = info[0].Split(' ')[1];
                            string val = "[" + info[1];
                            stats[key] = val;
                        }
                        else if (END == line)
                        {
                            // finish when we get end from server
                            //if(log.IsDebugEnabled)
                            //{
                            //    log.Debug(GetLocalizedString("stats finished"));
                            //}
                            break;
                        }

                        statsMaps[servers[i]] = stats;
                    }
                }
                catch (IOException e)
                {
                    message = e.Message.ToString();
                    //if(log.IsErrorEnabled)
                    //{
                    //    log.Error(GetLocalizedString("stats IOException"), e);
                    //}

                    try
                    {
                        sock.TrueClose();
                    }
                    catch (IOException ex)
                    {
                        message = ex.Message.ToString();
                        //if(log.IsErrorEnabled)
                        //{
                        //    log.Error(GetLocalizedString("failed to close some socket").Replace("$$Socket$$", sock.ToString()));
                        //}
                    }

                    sock = null;
                }

                if (sock != null)
                    sock.Close();
            }
            return statsMaps;
        }

        /// <summary>
        /// 获取服务器端缓存的数据信息
        /// </summary>
        /// <param name="serverArrayList">要访问的服务列表</param>
        /// <returns>返回信息</returns>
        public Hashtable CommonStats(ArrayList serverArrayList, GetStats statsCommand, string param)
        {

            param = Utils.StrIsNullOrEmpty(param) ? "" : param.Trim().ToLower();

            string commandstr = "stats";
            //转换stats命令参数
            switch (statsCommand)
            {
                case GetStats.Reset: { commandstr = "stats reset"; break; }
                case GetStats.Malloc: { commandstr = "stats malloc"; break; }
                case GetStats.Maps: { commandstr = "stats maps"; break; }
                case GetStats.Sizes: { commandstr = "stats sizes"; break; }
                case GetStats.Slabs: { commandstr = "stats slabs"; break; }
                case GetStats.Items: { commandstr = "stats items"; break; }
                case GetStats.States: { commandstr = "stats states"; break; }
                case GetStats.CachedDump:
                    {
                        string[] statsparams = Utils.SplitString(param, " ");
                        if (statsparams.Length == 2)
                            if (Utils.IsNumericArray(statsparams))
                                commandstr = "stats cachedump  " + param;

                        break;
                    }
                case GetStats.Detail:
                    {
                        if (string.Equals(param, "on") || string.Equals(param, "off") || string.Equals(param, "dump"))
                            commandstr = "stats detail " + param.Trim();

                        break;
                    }
                default: { commandstr = "stats"; break; }
            }
            //加载返回值
            string message = "";
            Hashtable stats = Stats(serverArrayList, commandstr, out message);
            if (message != "")
            {
                return null;
            }
            Hashtable returnMaps = new Hashtable();
            //Hashtable returnValue = new Hashtable();
            foreach (string key in stats.Keys)
            {
                //statsArray.Add(key);
                ArrayList statsArray = new ArrayList();
                Hashtable values = (Hashtable)stats[key];
                foreach (string key2 in values.Keys)
                {
                    switch (statsCommand)
                    {
                        case GetStats.Reset: { break; }
                        case GetStats.Malloc: { break; }
                        case GetStats.Maps: { break; }
                        case GetStats.Sizes: { break; }
                        case GetStats.Slabs: { break; }
                        case GetStats.Items:
                            {
                                string[] info = key2.Split(':');
                                if (info[0].Equals("items") && info[2].Equals("number"))
                                    statsArray.Add(key2 + ":" + values[key2]);

                                break;
                            }
                        case GetStats.States: { break; }
                        case GetStats.CachedDump:
                            {
                                statsArray.Add(key2);
                                break;
                            }
                        case GetStats.Detail:
                            {
                                break;
                            }
                        default: { break; }
                    }

                }
                returnMaps[key] = statsArray;
            }
            return returnMaps;
        }

        /// <summary>
        /// Stats命令行参数
        /// </summary>
        public enum GetStats
        {
            /// <summary>
            /// stats : 显示服务器信息, 统计数据等
            /// </summary>
            Default = 0,
            /// <summary>
            /// stats reset : 清空统计数据
            /// </summary>
            Reset = 1,
            /// <summary>
            /// stats malloc : 显示内存分配数据
            /// </summary>
            Malloc = 2,
            /// <summary>
            /// stats maps : 显示"/proc/self/maps"数据
            /// </summary>
            Maps = 3,
            /// <summary>
            /// stats sizes
            /// </summary>
            Sizes = 4,
            /// <summary>
            /// stats slabs : 显示各个slab的信息,包括chunk的大小,数目,使用情况等
            /// </summary>
            Slabs = 5,
            /// <summary>
            /// stats items : 显示各个slab中item的数目和最老item的年龄(最后一次访问距离现在的秒数)
            /// </summary>
            Items = 6,
            /// <summary>
            /// stats cachedump slab_id limit_num : 显示某个slab中的前 limit_num 个 key 列表
            /// </summary>
            CachedDump = 7,
            /// <summary>
            /// stats detail [on|off|dump] : 设置或者显示详细操作记录   on:打开详细操作记录  off:关闭详细操作记录 dump: 显示详细操作记录(每一个键值get,set,hit,del的次数)
            /// </summary>
            Detail = 8,
            /// <summary>
            /// 基本状态信息
            /// </summary>
            States = 9
        }

    }

}
